require"xml"
local USE_PROXY = false
local URL = "http://spreadsheets.google.com/pub?key=pHXX1t6i56MzVASWkD_4BeQ"
local SHEET_ID = 3
local WEEK_INDEX = 3
local MAX_RAID_ATTENDANCE = 4
local DEFAULT_RAID_ATTENDANCE = 3
local DEFAULT_OBJECTIVE = "Black Temple"

local TABLE_DATE_OFFSET = 4 + (WEEK_INDEX - 1) * MAX_RAID_ATTENDANCE
local TEMP = "temp.html"

local WGET = USE_PROXY and "wget" or "wget --proxy=off"

local NEVER_AVAILABLE = {
	Bignabe = true,
	Atoru = true,
	Durin = true,
}

local ATTENDANCE_OVERRIDE = {
	Kaldryn = 2,
	Bignabe = 0,
	Atoru = 0,
	Tutifruiti = 1,
	Grandspieds = 2,
}

local ROLE_RANGE = {
	Tank = { min = 3, max = 4 },
	Heal = { min = 8, max = 9 },
	Dps = { min = 12, },
}

local CLASSES = {
	"Guerrier",
	"Paladin",
	"Chaman",
	"Chasseur",
	"Voleur",
	"Druide",
	"Mage",
	"Prêtre",
	"Démoniste",
}

local ROLES = {
	"Tank",
	"Dps",
	"Heal",
}

function get_xml_data(url)
	assert(os.execute(WGET.." -q -O - \""..url.."\" | tidy -q -c -utf8 -asxml 2> /dev/null > "..TEMP))
	local f = io.open(TEMP, "r")
	local content = f:read("*a")
	f:close()
	os.remove(TEMP)
	return assert(xml.parse(content))
end

function get_data_entries(data)
	local entries = {}

	local body = assert(data:get_first_child("body"))
	for div in body:iterate_children("div") do
		if div:get_attribute("id") == "content" then
			for table in div:iterate_children("table") do
				for element in table:iterate_children("tr") do
					local line, value, has_value = {}, nil, false
					for cell in element:iterate_children("td") do
						local sub = cell:get_first_child("table")
						if sub then
							for element in sub:iterate_children("tr") do
								local line, value, has_value = {}, nil, false
								for cell in element:iterate_children("td") do
									value = cell:get_content():replace("\n", "")
									line[#line + 1] = value
									if value ~= "" then
										has_value = true
									end
								end
								if has_value then
									entries[#entries + 1] = line
								end
							end
						else
							value = cell:get_content():replace("\n", "")
							line[#line + 1] = value
							if value ~= "" then
								has_value = true
							end
						end
					end
					if has_value then
						entries[#entries + 1] = line
					end
				end
			end
		end
	end
	return entries
end

function get_rosters(entries)
	local players = {}
	local rosters = {
		{ Tank = {}, Dps = {}, Heal = {}, Available = {} },
		{ Tank = {}, Dps = {}, Heal = {}, Available = {} },
		{ Tank = {}, Dps = {}, Heal = {}, Available = {} },
		{ Tank = {}, Dps = {}, Heal = {}, Available = {} },
	}

	for i, line in ipairs(entries) do
		local player = line[2]
		if player == "Joueur" then
			for i = 1, 4 do
				rosters[i].date = line[i + TABLE_DATE_OFFSET]
			end
		elseif player == "Tank" then
			break
		end
		players[player] = {
			class = line[3],
			role = line[4],
			count = 0,
			unavailable = 0,
		}
		for i = 1, 4 do
			local data = line[i + TABLE_DATE_OFFSET]
			if data == "" and not NEVER_AVAILABLE[player] then data = "Available" end
			local table = rosters[i][data]
			if table then
				table[#table + 1] = player
			else
				players[player].unavailable = players[player].unavailable + 1
			end
		end
	end
	return players, rosters
end

function dump(s, ...)
	if s:find("%", 1, 1) then
		s = s:format(...)
	end
	print (s)
end

function dump_roster_table(data, players)
	dump("[size=14][b]%s[/b][/size]", data.date)
	dump("")
	dump("[list]")
	for _, class in ipairs(CLASSES) do
		local members = {}
		for _, role in ipairs(ROLES) do
			for _, name in ipairs(data[role]) do
				if players[name].class == class then
					members[#members + 1] = name
					players[name].count = players[name].count + 1
				end
			end
		end
		table.sort(members)
		dump("[*] [b]%s[/b] : %s", class, table.concat(members, ", "))
	end
	dump("[/list]")
	dump("")
	local c, total = {}, 0
	for _, role in ipairs(ROLES) do
		local count = #data[role]
		total = total + count
		local range = ROLE_RANGE[role]
		if range and (range.min and count < range.min) or (range.max and count > range.max) then
			count = "[color=red]"..count.."[/color]"
		end
		c[#c + 1] = role.." : "..count
	end
	c[#c + 1] = "Total : "..total
	dump(table.concat(c, ", "))
	table.sort(data.Available)
	dump("[b]Disponibles[/b] : %s", table.concat(data.Available, ", "))
	dump("[b]Objectif[/b] : %s", data.objective or DEFAULT_OBJECTIVE)
	dump("")
end

function dump_extra_data(players)
	dump("[hr]")

	local toomuch, toolittle = {}, {}
	for player, data in pairs(players) do
		local target = ATTENDANCE_OVERRIDE[player] or DEFAULT_RAID_ATTENDANCE
		if data.count > target and data.count == MAX_RAID_ATTENDANCE then
			toomuch[#toomuch + 1] = player
		elseif data.count < target and data.unavailable + data.count < MAX_RAID_ATTENDANCE then
			toolittle[#toolittle + 1] = player
		end
	end

	if #toomuch > 0 then
		table.sort(toomuch)
		dump("Joueurs participant à %d soirs : %s", MAX_RAID_ATTENDANCE, table.concat(toomuch, ", "))
	end
	if #toolittle > 0 then
		table.sort(toolittle)
		dump("Joueurs participant à %d soirs ou moins : %s", DEFAULT_RAID_ATTENDANCE - 1, table.concat(toolittle, ", "))
	end
end

function dump_data(rosters, players)
	for _, data in ipairs(rosters) do
		dump_roster_table(data, players)
	end
	dump_extra_data(players)
end

function main()
	local data = get_xml_data(URL.."&gid="..SHEET_ID)
	local entries = get_data_entries(data)
	local players, rosters = get_rosters(entries)
	dump_data(rosters, players)
end

main()
